﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace EssentialWebFramework.Models
{
    /// <summary>
    /// Guid 工厂类
    /// </summary>
    public class GuidFactory
    {
        /// <summary>
        /// 创建新的 GUID
        /// </summary>
        /// <returns></returns>
        public static string NewGuid()
        {
            return Guid.NewGuid().ToString();
        }

        /// <summary>
        /// 创建新的有序 Guid 字符串（使用当前时间）
        /// </summary>
        public static string NewSortedGuid()
        {
            return CreateSortedGuid(DateTime.Now).ToString();
        }

        /// <summary>
        /// 创建新的有序 Guid 字符串（传入时间参数）
        /// </summary>
        public static string NewSortedGuid(DateTime now)
        {
            return CreateSortedGuid(now).ToString();
        }

        /*
         *  1. GUID 由 16 位的 byte[] 生成。
         *  2. 生成 有序 Guid 的规则为前 8 位 为时间戳，后 8 位 为随机值。
         *  3. 小端模式下需要进行一些反转，否则仍是无序。
         *  4. 针对 MySQL 优化，参考文章：https://www.cnblogs.com/CameronWu/p/guids-as-fast-primary-keys-under-multiple-database.html
         */

        /// <summary>
        /// 创建新的有序 Guid
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static Guid CreateSortedGuid(DateTime dateTime)
        {
            byte[] randomBytes = RandomNumberGenerator.GetBytes(8);

            DateTime utcNow = dateTime.ToUniversalTime();
            long timestamp = utcNow.Ticks / 100L;
            byte[] timestampBytes = BitConverter.GetBytes(timestamp);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(timestampBytes);
            }

            byte[] guidBytes = new byte[16];
            Buffer.BlockCopy(timestampBytes, 0, guidBytes, 0, 8);
            Buffer.BlockCopy(randomBytes, 0, guidBytes, 8, 8);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(guidBytes, 0, 4);
                Array.Reverse(guidBytes, 4, 2);
                Array.Reverse(guidBytes, 6, 2);
            }

            return new Guid(guidBytes);
        }

        /// <summary>
        /// 根据有序 Guid 的获取时间
        /// </summary>
        /// <returns></returns>
        public static DateTime GetSortedGuidTime(string guid)
        {
            byte[] guidBytes = Guid.Parse(guid).ToByteArray();

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(guidBytes, 0, 4);
                Array.Reverse(guidBytes, 4, 2);
                Array.Reverse(guidBytes, 6, 2);
            }

            byte[] timestampBytes = new byte[8];
            Buffer.BlockCopy(guidBytes, 0, timestampBytes, 0, 8);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(timestampBytes);
            }


            long timestamp = BitConverter.ToInt64(timestampBytes, 0) * 100L;
            DateTime utcTime = new DateTime(timestamp);
            return utcTime.ToLocalTime();
        }
    }
}
